import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.URL;
import java.util.List;
import java.util.concurrent.Semaphore;


public class ConnectedDevice implements Runnable {
	//-----MEMBERS---------------------------------------------------------------------
	//device type fields
	public enum device_type {NOT_DETERMINED, CONTROLLER, VEHICLE, NOT_RECOGNIZED};
	private device_type connectedDeviceType = device_type.NOT_DETERMINED;
	
	//connection semantics fields
	//private final int DEVICE_PORT; //deprecated
	//private final int MAX_CONNECTIONS; //deprecated
	private Semaphore wasStopped = new Semaphore(1);
	
	//connection fields
	//private ServerSocket serverSocket; //deprecated
	private Socket socket;
	private InputStream streamIn;
	private OutputStream streamOut;
	
	//output fields
	private ConnectedDeviceBuffer outputBuffer;
	
	//-----METHODS---------------------------------------------------------------------
	//-----METHODS-PUBLIC----------------------------------------------------
	//constructors
	public ConnectedDevice(Socket connection, ConnectedDeviceBuffer writeBuf, ConnectedDeviceBuffer videoBuf) throws IOException {
		this.socket = connection;
		this.streamIn = this.socket.getInputStream();
		this.streamOut = this.socket.getOutputStream();
		this.outputBuffer = writeBuf;
		///TODO video buffer
	}
	
	//runnable
	public void run() {
		while( !wasStopped() ){
			testProto();//TODO clean up and class-ify this bit
		}//we're done. close down the sockets
		//now try shutting ourself down
		
		try{
			this.socket.close();
		}catch(IOException ioErr){
			throw new RuntimeException("Error closing the socket!", ioErr);
		}//everything has been cleaned up. take care of some logging and rejoin

		System.out.println("The socket has been closed.");
	}
	
	//accessors
	public device_type getDeviceType(){
		return connectedDeviceType;
	}
	
	public ConnectedDeviceBuffer getBuf() {
		return this.outputBuffer;
	}
	
	public synchronized boolean wasStopped(){
		return ( wasStopped.availablePermits() == 0 )? true : false ;
	}

	//mutators
	public synchronized boolean requestStop(){//return true if the stop was successfully requested
		return wasStopped.tryAcquire();
	}

	//-----METHODS-PRIVATE---------------------------------------------------
	//mutators
	private void identifyConnectedDevice(){
		//read the first start byte of the first packet
		//read the first control byte of the first packet
		//read the second control byte of the first packet
	}
	
	// \/\/\/ TODO !!! break out the protocol methods into protocol classes !!! TODO \/\/\/
	private void testProto(){
		if(this.connectedDeviceType == device_type.CONTROLLER){//TODO WAT WHY
			System.out.println("CON - Starting the controller subroutine");
			byte[] packetIn = {0, 0, 0, 0, 0, 0, 0, 0};
			for(int i = 0; i < packetIn.length; i++){
				int byteIn = 69;
				try {
					byteIn = streamIn.read();
					if(byteIn == -1){
						System.out.println("CON - The input stream from the controller was closed. Exiting...");
						//int[] stopMsg = {0, 0, 0, 0, 0, 0, 0, 0};
						//outputBuffer.produce(stopMsg);
						this.requestStop();
						return;
					}
					//System.out.println("CON - Byte " + i + " of the first packet read from ctrl was " + byteIn);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				packetIn[i] = (byte) byteIn;
			}

			while(!outputBuffer.produce(packetIn)){}
		}
		else if(this.connectedDeviceType == device_type.VEHICLE){
			//don't write out just yet!
			System.out.println("VEH - Starting the vehicle subroutine");
			
			byte[] byteRecvd = outputBuffer.consume();
			try{
				streamOut.write(byteRecvd);
				
			}catch(IOException ioErr){
				ioErr.printStackTrace();
				this.requestStop();
			}
		}
		else{
			System.out.println("Device type not recognized");
			this.requestStop();
		}
	}
	// /\/\/\ TODO !!! break out the protocol methods into protocol classes !!! TODO /\/\/\
	
	//TODO the following method MUST BE REMOVED!!
	public synchronized void setDeviceTypeForTest(device_type testType){
		this.connectedDeviceType = testType;
	}
}
